package edu.del.newsreleasesystem.aop;

import edu.del.newsreleasesystem.config.RabbitMQConfig;
import edu.del.newsreleasesystem.entity.News;
import edu.del.newsreleasesystem.mq.message.NewsSyncMessage;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.amqp.rabbit.connection.CorrelationData;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.stereotype.Component;

import java.util.Date;
import java.util.UUID;

/**
 * 切面：负责在新闻发布/更新/删除后，自动发送同步消息到 MQ
 */
@Aspect
@Component
@Slf4j
@RequiredArgsConstructor
public class NewsSyncAspect {

    private final RabbitTemplate rabbitTemplate;

    /**
     * 发布新闻
     * @param joinPoint 切点
     * @param retVal 返回值
     * @return 返回值
     */
    @AfterReturning(pointcut = "execution(* edu.del.newsreleasesystem.service.NewsService.publishNews(..))", returning = "retVal")
    public Object afterPublishNews(JoinPoint joinPoint, Object retVal){
        // 获取参数
        Object[] args = joinPoint.getArgs();

        // 转换 参数为 News 对象
        News news = (News) args[0];

        // 构建同步消息
        NewsSyncMessage message =buildMessage(news.getId(), NewsSyncMessage.OperationType.PUBLISH);

        // 发送消息
        send(message);

        log.info("已发送新闻同步（删除）消息到 RabbitMQ，新闻ID: {}", message.getNewsId());

        return retVal;
    }

    /**
     * 更新新闻
     * @param joinPoint 切点
     * @param retVal 返回值
     * @return 返回值
     */
    @AfterReturning(pointcut = "execution(* edu.del.newsreleasesystem.service.NewsService.updateNews(..))", returning = "retVal")
    public Object afterUpdateNews(JoinPoint joinPoint, Object retVal){
        // 获取参数
        Object[] args = joinPoint.getArgs();

        // 转换 参数为 News 对象
        News news = (News) args[0];

        // 构建同步消息
        NewsSyncMessage message =buildMessage(news.getId(), NewsSyncMessage.OperationType.UPDATE);

        // 发送消息
        send(message);

        log.info("已发送新闻同步（删除）消息到 RabbitMQ，新闻ID: {}", message.getNewsId());

        return retVal;
    }

    /**
     * 删除新闻
     * @param joinPoint 切点
     * @param retVal 返回值
     * @return 返回值
     */
    @AfterReturning(pointcut = "execution(* edu.del.newsreleasesystem.service.NewsService.updateNews(..))", returning = "retVal")
    public Object afterDeleteNews(JoinPoint joinPoint, Object retVal){
        // 获取参数
        Object[] args = joinPoint.getArgs();

        // 转换 参数为 News 对象
        News news = (News) args[0];

        // 构建同步消息
        NewsSyncMessage message =buildMessage(news.getId(), NewsSyncMessage.OperationType.DELETE);

        // 发送消息
        send(message);

        log.info("已发送新闻同步（删除）消息到 RabbitMQ，新闻ID: {}", message.getNewsId());

        return retVal;
    }



    /**
     * 发送同步消息
     * @param message 同步消息
     */
    private void send(NewsSyncMessage  message) {
        CorrelationData correlationData = new CorrelationData();
        correlationData.setId(UUID.randomUUID().toString());
        rabbitTemplate.convertAndSend(
                RabbitMQConfig.TOPIC_EXCHANGE,
                RabbitMQConfig.SYNC_ROUTING_KEY,
                message,
                correlationData
        );
    }

    /**
     * 构建同步消息
     * @param newsId 新闻id
     * @param operationType 操作类型
     * @return 同步消息
     */
    private NewsSyncMessage buildMessage(Integer newsId, NewsSyncMessage.OperationType operationType) {
        return new NewsSyncMessage(
                newsId,
                operationType,
                new Date(),
                "SYSTEM"
        );
    }
}
